package dipl.algorithm.math.fp.primitive.op;

import dipl.algorithm.math.primitive.Side;
import dipl.algorithm.math.fp.primitive.Point2df;
import dipl.algorithm.math.fp.primitive.Vector2df;

/**
 * Class provides operations on vectors
 */
public class Vector2dOps {

	//
	// PUBLIC METHODS
	//

	/**
	 * Calculates (smaller) angle between both given vectors.
	 * If length of at least one of the given vectors is zero, zero is returned
	 * @param fpMath
	 * @param v1
	 * @param v2
	 * @return
	 */
	public static double Angle( Vector2df v1, Vector2df v2 ) {
		if( v1.x == 0.0 && v1.y == 0.0 )
			return 0.0;
		if( v2.x == 0.0 && v2.y  == 0.0 )
			return 0.0;
		double a = DotProduct( v1, v2 )/(v1.Norm()*v2.Norm());
		return Math.acos( a );
	}

	public static double Area( Vector2df v0, Vector2df v1 ) {
		return v0.x*(v0.y+v1.y)-v0.y*(v0.x+v1.x);
	}

	public static double Area( double v0x, double v0y, double v1x, double v1y ) {
		return v0x*(v0y+v1y)-v0y*(v0x+v1x);
	}

	/**
	 * Calculates dot product of given two vectors
	 * @param fpMath
	 * @param v1
	 * @param v2
	 * @return
	 */
	public static double DotProduct( Vector2df v1, Vector2df v2 ) {
		return v1.x*v2.x+v1.y*v2.y;
	}

	/**
	 * Returns difference vector (q.x - p.x, q.y - p.y)
	 * @param fpMath
	 * @param p
	 * @param q
	 * @return
	 */
	public static Vector2df DifferenceVector( Point2df p, Point2df q ) {
		return new Vector2df( q.x-p.x, q.y-p.y );
	}

	/**
	 * Calculates difference vector (q.x - p.x, q.y - p.y)
	 * @param fpMath
	 * @param p
	 * @param q
	 * @param result
	 */
	public static void DifferenceVector(Point2df p, Point2df q,/*out*/ Vector2df result ) {
		result.x = q.x-p.x;
		result.y = q.y-p.y;
	}

	/**
	 * Tests whether or not both vectors make a right turn.
	 * In other words it is tested whether or not v1 is right of v0.
	 * @param fpMath
	 * @param v0
	 * @param v1
	 * @return
	 */
	public static boolean MakeRightTurn( Vector2df v0, Vector2df v1 ) {
		return Area( v0, v1 ) < 0.0;
	}

	/**
	 * Calculates whether v1 lies to the right, on or to the left of v0.
	 * @param fpMath
	 * @param v0
	 * @param v1
	 * @return
	 */
	public static Side WhichSide( Vector2df v0, Vector2df v1 ) {
		double c = Math.signum( Area( v0, v1 ) );
		if( c < 0.0 )
			return Side.Right;
		if( c > 0.0 )
			return Side.Left;
		return Side.Onto;
	}

	/**
	 * Calculates whether (v1x,v1y) lies to the right, on or to the left of (v0x,v0y).
	 * @param fpMath
	 * @param v0x
	 * @param v0y
	 * @param v1x
	 * @param v1y
	 * @return
	 */
	public static Side WhichSide( double v0x, double v0y, double v1x, double v1y ) {
		double c = Math.signum( Area( v0x, v0y, v1x, v1y ) );
		if( c < 0.0 )
			return Side.Right;
		if( c > 0.0 )
			return Side.Left;
		return Side.Onto;
	}
}
